package com.nav.rummy.core;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Stack;

public class Rummy {
	public static int RUMMY_NOT_STARTED = 0, RUMMY_STARTED = 1, RUMMY_ENDED = 2;
	private ArrayList<Player> p = new ArrayList<Player>();
	private Deck closedDeck = new Deck(Card.newPack());
	private Stack<Card> openDeck = new Stack<Card>();
	private Card joker;
	private int curPlayerInd = 0;
	private int status = RUMMY_NOT_STARTED;
	
	public Card peekOpenDeck() {
		return openDeck.size() > 0 ? openDeck.peek() : null;
	}
	
	public void start() {
		status = RUMMY_STARTED;
	}
	
	/**
	 * @param name name of the player who makes the first move
	 */
	public void setCurPlayer(String name) {
		for(int i = 0; i < p.size(); i++) {
			if(p.get(i).getName().equalsIgnoreCase(name)) {
				curPlayerInd = i;
				return;
			}
		}
	}
	
	public boolean isStarted() {
		return status > RUMMY_NOT_STARTED;
	}
	
	public int getStatus() {
		return status;
	}
	
	public void setJoker(char r, char s) {
		joker = closedDeck.remove(Rank.getInstance(r),
				Suit.getInstance(s));
	}
	
	public void addPlayer(String name) {
		p.add(new Player(name));
	}
	
	public void addCard(String playerName, char r, char s) {
		for(Player player : p) {
			if(player.getName().equalsIgnoreCase(playerName))
				player.addCard(closedDeck.remove(
					Rank.getInstance(r), Suit.getInstance(s)));
		}
	}
	
	public void addOpenCard(char r, char s) {
		openDeck.add(closedDeck.remove(Rank.getInstance(r),
				Suit.getInstance(s)));
	}
	
	public boolean allCardsKnown() {
		return p.get(curPlayerInd).allCardsKnown();
	}
	
	public Player getCurPlayer() {
		return p.get(curPlayerInd);
	}
	
	public String getInCardSuggestion() {
		return p.get(curPlayerInd).getInCardSuggestion(closedDeck, openDeck.peek(), joker);
	}
	
	public void inClosedCard(char r, char s) {
		System.out.println("inClosedCard " + r + s);
		p.get(curPlayerInd).addCard(closedDeck.remove(Rank.getInstance(r), Suit.getInstance(s)));
		System.out.println("closedDeck: " + closedDeck);
		System.out.println(p.get(curPlayerInd));
	}
	
	public void inOpenCard() {
		System.out.println("inOpenCard");
		p.get(curPlayerInd).addCard(openDeck.pop());
		System.out.println("openDeck: " + openDeck);
		System.out.println(p.get(curPlayerInd));
	}
	
	public String getStrOutCardSuggestion() {
		return p.get(curPlayerInd).getStrOutCardSuggestion(p.get((curPlayerInd + 1) % p.size()).getCards(), joker);
	}
	
	public ArrayList<IArrangement> getArrangement(String playerName) {
		for(Player player : p) {
			if(player.getName().equalsIgnoreCase(playerName))
				return player.getArrangement();
		}
		return null;
	}
	
	public Card getOutCardSuggestion() {
		return p.get(curPlayerInd).getOutCardSuggestion(p.get((curPlayerInd + 1) % p.size()).getCards(), joker);
	}
	
	public int getOutCardSuggestionInd() {
		return p.get(curPlayerInd).getOutCardSuggestionInd(p.get((curPlayerInd + 1) % p.size()).getCards(), joker);
	}
	
	public void outOpenCard(char r, char s) {
		System.out.println("outOpenCard " + r + s);
		openDeck.push(outCard(r, s));
		System.out.println("openDeck: " + openDeck);
	}
	
	public void outFinishCard(char r, char s) {
		System.out.println("outFinishCard " + r + s);
		outCard(r, s);
		finish();
	}
	
	private void finish() {
		status = RUMMY_ENDED;
	}
	
	private Card outCard(char r, char s) {
		Card card = p.get(curPlayerInd).removeCard(Rank.getInstance(r), Suit.getInstance(s));
		if (card == null)
			card = closedDeck.remove(Rank.getInstance(r), Suit.getInstance(s));
		System.out.println(p.get(curPlayerInd));
		curPlayerInd = (curPlayerInd + 1) % p.size();
		return card;
	}
	
	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		Rummy rummy = new Rummy();
		String option = "m";
		int optnum = 0;
		String curPlayer = null;
		boolean forceSugg = false;
		for (String arg : args) {
			if (arg.startsWith("-")) {
				option = arg.substring(1);
				if (option.startsWith("f"))
					forceSugg = true;
				optnum = 0;
				continue;
			} else
				optnum++;
			if (option.startsWith("p")) {
				if (optnum == 1) {
					curPlayer = arg;
					rummy.addPlayer(curPlayer);
				} else {
					char r = arg.charAt(0);
					char s = arg.charAt(1);
					if (curPlayer != null)
						rummy.addCard(curPlayer, r, s);
				}
			}
			if (option.startsWith("j")) {
				char r = arg.charAt(0);
				char s = arg.charAt(1);
				rummy.setJoker(r, s);
			}
			if (option.startsWith("o")) {
				char r = arg.charAt(0);
				char s = arg.charAt(1);
				rummy.addOpenCard(r, s);
			}
		}
		System.out.println("In card format: <InDeck><InCardRank><InCardSuit>");
		System.out.println("InDeck format: (O)penDeck/(C)losedDeck");
		System.out
				.println("InCardRank and InCardSuit are optional for InDeck format O");
		System.out.println("InCardRank format: A/2/3/4/5/6/7/8/9/(T)en/J/Q/K");
		System.out
				.println("InCardSuit format: (C)lub/(D)iamond/(H)eart/(S)pade");
		System.out.println("Sample in card format: O2C");

		System.out
				.println("Out card format: <OutDeck><OutCardRank><OutCardSuit>");
		System.out.println("OutDeck format: (O)penDeck/(F)inish");
		System.out.println("OutCardRank format: A/2/3/4/5/6/7/8/9/(T)en/J/Q/K");
		System.out
				.println("OutCardSuit format: (C)lub/(D)iamond/(H)eart/(S)pade");
		System.out.println("Sample out card format: O9H");

		System.out.println("All inputs are case insensitive");

		BufferedReader inRdr = new BufferedReader(new InputStreamReader(
				System.in));
		while (true) {
			System.out.println("Joker: " + rummy.joker);
			System.out.println("Closed Deck: " + rummy.closedDeck);
			System.out.println("Open Deck: " + rummy.openDeck);
			for (Player player : rummy.p)
				System.out.println(player);
			String sugg = null;
			if (rummy.allCardsKnown()) {
				sugg = rummy.getInCardSuggestion();
				if (!forceSugg)
					System.out.println("In card suggestion for "
							+ rummy.getCurPlayer().getName() + ": " + sugg);
			}
			System.out.print("In card by " + rummy.getCurPlayer().getName() + ": ");
			if (rummy.allCardsKnown() && forceSugg)
				System.out.print(sugg);
			String inCard = inRdr.readLine();
			if (rummy.allCardsKnown() && forceSugg)
				inCard = sugg + inCard;
			if (inCard.length() < 1) {
				System.out
						.println("Incorrect in card format, please enter again");
				continue;
			}
			if (inCard.charAt(0) == 'C' || inCard.charAt(0) == 'c') {
				if (inCard.length() >= 3)
					rummy.inClosedCard(inCard.charAt(1), inCard.charAt(2));
			}
			else if (inCard.charAt(0) == 'O' || inCard.charAt(0) == 'o')
				rummy.inOpenCard();
			String outCard = null;
			while(true) {
				if (rummy.allCardsKnown()) {
					sugg = rummy.getStrOutCardSuggestion();
					if (!forceSugg)
						System.out.println("Out card suggestion for "
								+ rummy.getCurPlayer().getName() + ": " + sugg);
				}
				System.out.print("Out card by " + rummy.getCurPlayer().getName() + ": ");
				if (rummy.allCardsKnown() && forceSugg)
					System.out.print(sugg);
				outCard = inRdr.readLine();
				if (rummy.allCardsKnown() && forceSugg)
					outCard = sugg + outCard;
				if (outCard.length() < 1 || outCard.charAt(0) != 'F' && outCard.charAt(0) != 'f' && outCard.charAt(0) != 'O' && outCard.charAt(0) != 'o') {
					System.out
							.println("Incorrect out card format, please enter again");
					continue;
				}
				break;
			}
			if (outCard.charAt(0) == 'F' || outCard.charAt(0) == 'f') {
				rummy.outFinishCard(outCard.charAt(1), outCard.charAt(2));
				break;
			} else
				rummy.outOpenCard(outCard.charAt(1), outCard.charAt(2));
		}
		inRdr.close();
	}
}
